/*
package org.eliza.utils.color is command line color library.
Support rich color rendering output, universal API method, compatible with Windows system

Source code and other details for the project are available at GitHub:

	https://github.com/gookit/color

More usage please see README and tests.
*/
package   org.eliza.base.color

import java.io.InputStream
import java.io.OutputStream


// color render templates
//
// ESC 操作的表示:
//
//	"\033"(Octal 8进制) = "\x1b"(Hexadecimal 16进制) = 27 (10进制)


// StartSet chars
const val StartSet = "\u001b1b["

// ResetSet close all properties.
const val ResetSet = "\u001b1b[0m"

// SettingTpl :String.
const val SettingTpl = "\u001b1b[%sm"

// FullColorTpl for build color code
const val FullColorTpl = "\u001b1b[%sm%s\u001b1b[0m"

// CodeSuffix :String for color code.
const val CodeSuffix = "[0m"

// CodeExpr regex to clear color codes eg "\033[1;36mText\x1b[0m"
val CodeExpr: String = "\\033\\[[\\d;?]+m"

// Enable switch color render and display
//
// NOTICE:
// if ENV: NO_COLOR is not empty, will disable color render.
var Enable = System.getenv("NO_COLOR") == ""

// RenderTag render HTML tag on call color.Xprint, color.PrintX
var RenderTag = true

// debug mode for development.
//
// set env:
// 	COLOR_DEBUG_MODE=on
// or:
// 	COLOR_DEBUG_MODE=on go run ./_examples/envcheck.go
var debugMode = System.getenv("COLOR_DEBUG_MODE") == "on"

// inner errors record on detect color level
//innerErrs []error
// output the default io.Writer message print
//var output io.Writer = os.Stdout
var output: OutputStream = java.io.OutputStream.nullOutputStream()

// mark current env, It's like in `cmd.exe`
// if not in windows, it's always False.
var isLikeInCmd: Boolean = false

// the color support level for current terminal
// needVTP - need enable VTP, only for Windows OS
//colorLevel, needVTP = detectTermColorLevel()
var colorLevel = ColorLevelNone

// match color codes
var codeRegex = Regex(CodeExpr)
// mark current env is support color.
// Always: isLikeInCmd != supportColor
// supportColor = IsSupportColor()

// TermColorLevel Get the currently supported color level
fun TermColorLevel(): ColorLevel {
    return colorLevel
}

// SupportColor Whether the current environment supports color output
fun SupportColor(): Boolean {
    return colorLevel > ColorLevelNone
}

// Support16Color on the current ENV
// fun Support16Color() Boolean {
// 	return colorLevel > terminfo.ColorLevelNone
// }

// Support256Color Whether the current environment supports 256-color output
fun Support256Color(): Boolean {
    return colorLevel > ColorLevelBasic
}

// SupportTrueColor Whether the current environment supports (RGB)True-color output
fun SupportTrueColor(): Boolean {
    return colorLevel > ColorLevelHundreds
}

/*************************************************************
 * global settings
 *************************************************************/

// Set console color attributes
fun Set(vararg colors: Color): Pair<Int, Nothing> {
//    code : = Colors2code(colors...)
//    err : = SetTerminal(code)
    return Pair(0, error(""))
}

// Reset reset console color attributes
fun Reset() {
    ResetTerminal()
}

// Disable disable color output
fun Disable(): Boolean {
//    oldVal = Enable
//    Enable = false
//    return oldVal
    return true
}

// NotRenderTag on call color.Xprint, color.PrintX
fun NotRenderTag() {
    RenderTag = false
}

// SetOutput set default colored text output
fun SetOutput(w: OutputStream) {
}

// ResetOutput reset output
fun ResetOutput() {
//    output = os.Stdout
}

// ResetOptions reset all package option setting
fun ResetOptions() {
    RenderTag = true
    Enable = true
//    output = os.Stdout
}

// ForceSetColorLevel force open color render
fun ForceSetColorLevel(level: ColorLevel): ColorLevel {
    val oldLevelVal = colorLevel
    colorLevel = level
    return oldLevelVal
}

// ForceColor force open color render
fun ForceColor(): ColorLevel {
    return ForceOpenColor()
}

// ForceOpenColor force open color render
fun ForceOpenColor(): ColorLevel {
    // TODO should set level to ?
    return ForceSetColorLevel(ColorLevelMillions)
}

// IsLikeInCmd check result
//
// Deprecated: please don't use
fun IsLikeInCmd(): Boolean {
    return isLikeInCmd
}

// InnerErrs info

/*************************************************************
 * render color code
 *************************************************************/

// RenderCode render message by color code.
//
// Usage:
//
//	msg := RenderCode("3;32;45", "some", "message")
fun RenderCode(code: String, vararg args: Any): String {
    val ln = args.size
    if (ln == 0) {
        return ""
    }
    val message = args.joinToString()
    if (code.isEmpty()) {
        return message
    }
    // disabled OR not support color
    if (!Enable || !SupportColor()) {
        return ClearCode(message)
    }

    // return fmt.Sprintf(FullColorTpl, code, message)
    return StartSet + code + "m" + message + ResetSet
}


// Render:String render a :String with color code.
//
// Usage:
//
//	msg := Render:String("3;32;45", "a message")
fun RenderString(code: String, str: String): String {
    if (code.length == 0 || str == "") {
        return str
    }

    // disabled OR not support color
    if (!Enable || !SupportColor()) {
        return ClearCode(str)
    }

    // return fmt.Sprintf(FullColorTpl, code, str)
    return StartSet + code + "m" + str + ResetSet
}

// ClearCode clear color codes.
//
// eg:
//
//	"\033[36;1mText\x1b[0m" -> "Text"
fun ClearCode(str: String): String {
    if (!str.contains(CodeSuffix)) {
        return str
    }
    return codeRegex.replace(str, "")
}
